/*
 *  encfsVaultCntrl.c
 *  EncfsVault
 *
 *  Created by Stephen Baker on 12/6/07.
 *  Copyright 2007 ChuckKnowsBest.com. All rights reserved.
 *
 */

/*
Leopard
 			<array>
				<string>builtin:smartcard-sniffer,privileged</string>
				<string>loginwindow:login</string>
				<string>builtin:reset-password,privileged</string>
				<string>EncfsVault:user-mount,privileged</string>
				<string>builtin:auto-login,privileged</string>
				<string>builtin:authenticate,privileged</string>
				<string>HomeDirMechanism:login,privileged</string>
				<string>HomeDirMechanism:status</string>
				<string>MCXMechanism:login</string>
				<string>loginwindow:success</string>
				<string>loginwindow:done</string>
			</array>
Tiger
			<key>mechanisms</key>
			<array>
				<string>builtin:auto-login,privileged</string>
				<string>loginwindow_builtin:login</string>
				<string>builtin:reset-password,privileged</string>
				<string>EncfsVault:user-mount,privileged</string> 
				<string>authinternal</string>
				<string>builtin:getuserinfo,privileged</string>
				<string>builtin:sso,privileged</string>
				<string>HomeDirMechanism:login,privileged</string>
				<string>HomeDirMechanism:status</string>
				<string>MCXMechanism:login</string>
				<string>loginwindow_builtin:success</string>
				<string>loginwindow_builtin:done</string>
			</array>
			

*/

#include <CoreFoundation/CoreFoundation.h>
#include <Security/AuthorizationDB.h>
#include <getopt.h>

void reportError(const char* errMsg, int exitCode)
{
	perror(errMsg);
	exit(exitCode);
}

void showUsage()
{
	printf("encfsVaultCntrl [ --status | --enable | --disable ]\n" );
	printf("	status  - prints the enable status of EncfsVault (default opt)\n");
	printf("	enable  - enable EncfsVault login\n");
	printf("	disable - disable EncfsVault login\n\n");
	exit( 1 );
}

#define RESET_PASSWORD "builtin:reset-password,privileged"
#define ENCFS_ITEM "EncfsVault:user-mount,privileged"

enum RunMode { statusMode, enableMode, disableMode };

int main(int argc, char *argv[])
{
	bool okToWriteDict = false;
    CFDictionaryRef login_dict;
    OSStatus status;
    AuthorizationRef authRef;	
	const char* loginRight = "system.login.console";
	int c = 0;
	int mode = statusMode;
	
	while (1)
	{
		static struct option long_options[] =
		{
			{"status",  no_argument, 0, 's'},
			{"enable",  no_argument, 0, 'e'},
			{"disable", no_argument, 0, 'd'},
			{0, 0, 0, 0}
		};
		
		int option_index = 0;
		c = getopt_long (argc, argv, ":sed",
						 long_options, &option_index);
		
		if(c == -1)
		{ 
			break; 
		}
		
		switch (c)
		{
			case 's':
				mode = statusMode;
				break;
				
			case 'e':
				mode = enableMode;
				break;
				
			case 'd':
				mode = disableMode;
				break;
			
			default:
				showUsage();
				break;
		}
	}	
	
    status = AuthorizationCreate(NULL, NULL, 0, &authRef);
    if(status == 0)
	{ 
		status = AuthorizationRightGet(loginRight, &login_dict);
		if(status == 0) 
		{
			CFArrayRef arrayRef;
			if(CFDictionaryGetValueIfPresent(login_dict, CFSTR("mechanisms"), (void*)&arrayRef))
			{
				CFMutableArrayRef newMechanisms = CFArrayCreateMutableCopy(NULL, 0, arrayRef);
				if(newMechanisms)
				{				
					if(mode == disableMode)
					{
						CFIndex index = CFArrayGetFirstIndexOfValue(newMechanisms,
																	CFRangeMake(0, CFArrayGetCount(newMechanisms)), CFSTR(ENCFS_ITEM));
												
						if (index != -1)
						{
							CFArrayRemoveValueAtIndex(newMechanisms, index);
							okToWriteDict = true;
						}
						else
						{
							reportError("Failed to get index for encfs item", 5);
						}
					}
					else if(mode == enableMode)
					{
						CFIndex index = CFArrayGetFirstIndexOfValue(newMechanisms,
																	CFRangeMake(0, CFArrayGetCount(newMechanisms)), CFSTR(ENCFS_ITEM));
						if(index == -1)
						{
							index = CFArrayGetFirstIndexOfValue(newMechanisms,
																CFRangeMake(0, CFArrayGetCount(newMechanisms)), CFSTR(RESET_PASSWORD));
						
							if (index != -1)
							{
								CFArrayInsertValueAtIndex(newMechanisms, index+1, CFSTR(ENCFS_ITEM));
								okToWriteDict = true;
							}
							else
							{
								reportError("Failed to get index for reset-pass", 6);
							}
						}
						else
						{
							printf("EncfsVault was already enabled\n");
						}
					}
					else
					{
						okToWriteDict = false;
						CFIndex index = CFArrayGetFirstIndexOfValue(newMechanisms,
																	CFRangeMake(0, CFArrayGetCount(newMechanisms)), CFSTR(ENCFS_ITEM));
						if(index == -1)
						{
							printf("EncfsVault is disabled\n");
						}
						else
						{
							printf("EncfsVault is enabled\n");
						}
					}
					
					if(okToWriteDict)
					{
						CFMutableDictionaryRef new_login_dict 
						= CFDictionaryCreateMutableCopy(NULL, 0, login_dict);
						
						CFDictionarySetValue(new_login_dict, CFSTR("mechanisms"), newMechanisms);
						
						if(AuthorizationRightSet(authRef, loginRight, new_login_dict,
												 NULL, NULL, NULL) != 0)
						{
							reportError("Failed to set new login info", 7);
						}
					}
				}	
				else
				{
					reportError("Failed to create new array", 4);
				}
			}
			else
			{
				reportError("Failed to get item mechanisms", 3);
			}
		}
		else
		{
			reportError("Auth RightGet failed", 2);
		}
	}
	else
	{
		reportError("Auth Create failed", 1);
	}
	
	return 0;
}
